﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Infusion.Silverlight.Controls.Ribbon;
#endregion

namespace Infusion.Silverlight.Controls.Input
{
    #region Delegates...
    public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
    #endregion

    #region : NumericUpDown :
    #region Template Parts...
    [TemplatePart(Name = NumericUpDown.NumericUpDownLayoutRoot, Type = typeof(Grid))]
    [TemplatePart(Name = NumericUpDown.ImgImage, Type = typeof(Image))]
    [TemplatePart(Name = NumericUpDown.TxtLabel, Type = typeof(TextBlock))]
    [TemplatePart(Name = NumericUpDown.CanvasMainBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasMainBackground, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.TbxText, Type = typeof(TextBlock))]
    [TemplatePart(Name = NumericUpDown.CanvasUpOuterBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasUpInnerBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasUpBackground, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasUpClickSurface, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasDownOuterBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasDownInnerBorder, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasDownBackground, Type = typeof(Canvas))]
    [TemplatePart(Name = NumericUpDown.CanvasDownClickSurface, Type = typeof(Canvas))]
    #endregion
    public class NumericUpDown : Control, IRibbonTabGroupItem
    {
        #region Events...
        public event ValueChangedEventHandler ValueChanged;
        #endregion

        #region TemplatePart Names...
        public const string NumericUpDownLayoutRoot = "NumericUpDownLayoutRoot";
        public const string ImgImage = "ImgImage";
        public const string TxtLabel = "TxtLabel";
        public const string CanvasMainBorder = "CanvasMainBorder";
        public const string CanvasMainBackground = "CanvasMainBackground";
        public const string TbxText = "TbxText";
        public const string CanvasUpOuterBorder = "CanvasUpOuterBorder";
        public const string CanvasUpInnerBorder = "CanvasUpInnerBorder";
        public const string CanvasUpBackground = "CanvasUpBackground";
        public const string CanvasUpClickSurface = "CanvasUpClickSurface";
        public const string CanvasDownOuterBorder = "CanvasDownOuterBorder";
        public const string CanvasDownInnerBorder = "CanvasDownInnerBorder";
        public const string CanvasDownBackground = "CanvasDownBackground";
        public const string CanvasDownClickSurface = "CanvasDownClickSurface";
        #endregion

        #region TemplatePart Variables...
        internal Grid numericUpDownLayoutRoot;
        internal Image imgImage;
        internal TextBlock txtLabel;
        internal Canvas canvasMainBorder;
        internal Canvas canvasMainBackground;
        internal TextBox tbxText;
        internal Canvas canvasUpOuterBorder;
        internal Canvas canvasUpInnerBorder;
        internal Canvas canvasUpBackground;
        internal Canvas canvasUpClickSurface;
        internal Canvas canvasDownOuterBorder;
        internal Canvas canvasDownInnerBorder;
        internal Canvas canvasDownBackground;
        internal Canvas canvasDownClickSurface;
        #endregion

        #region Class Variables...
        private bool templateApplied = false;
        private bool textBoxHasFocus = false;
        private RibbonTabGroup parentRibbonTabGroup;
        #endregion

        #region Dependency Properties...
        #region ValueProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Value dependency property.
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value",
            typeof(double),
            typeof(NumericUpDown),
            new PropertyMetadata(new PropertyChangedCallback(ValuePropertyChanged)));
        #endregion

        #region LabelProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Label dependency property.
        /// </summary>
        public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
                "Label",
                typeof(string),
                typeof(NumericUpDown),
                new PropertyMetadata(new PropertyChangedCallback(LabelPropertyChanged)));
        #endregion

        #region ImageSourceProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.ImageSource dependency property.
        /// </summary>
        public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
            "ImageSource",
            typeof(string),
            typeof(NumericUpDown),
            new PropertyMetadata(new PropertyChangedCallback(ImageSourcePropertyChanged)));
        #endregion

        #region IncrementProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Increment dependency property.
        /// </summary>
        public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register(
            "Increment",
            typeof(double),
            typeof(NumericUpDown),
            null);
        #endregion

        #region MaximumProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Maximum dependency property.
        /// </summary>
        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
            "Maximum",
            typeof(double),
            typeof(NumericUpDown),
            null);
        #endregion

        #region MinimumProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Minimum dependency property.
        /// </summary>
        public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
            "Minimum",
            typeof(double),
            typeof(NumericUpDown),
            null);
        #endregion

        #region UnitsProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Input.NumericUpDown.Units dependency property.
        /// </summary>
        public static readonly DependencyProperty UnitsProperty = DependencyProperty.Register(
            "Units",
            typeof(string),
            typeof(NumericUpDown),
            null);
        #endregion
        #endregion

        #region Dependency Property Changed Handlers...
        #region ValuePropertyChanged
        private static void ValuePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != null)
            {
                NumericUpDown numericUpDown = (NumericUpDown)obj;

                double oldValue = double.NaN;
                if (args.OldValue != null)
                    oldValue = (double)args.OldValue;

                if ((double)args.NewValue != oldValue)
                    numericUpDown.RaiseValueChangedEvent((double)args.NewValue);
            }
        }
        #endregion

        #region LabelPropertyChanged
        private static void LabelPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion

        #region ImageSourcePropertyChanged
        private static void ImageSourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
        }
        #endregion
        #endregion

        #region Constructor(s)...
        #region NumericUpDown
        public NumericUpDown() : base()
        {
            DefaultStyleKey = typeof(NumericUpDown);
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region parentRibbonTabGroup_ColumnWidthChanged
        private void parentRibbonTabGroup_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            if (e.ColumnIndex == (int)GetValue(Grid.ColumnProperty) && numericUpDownLayoutRoot != null)
            {
                numericUpDownLayoutRoot.ColumnDefinitions[1].Width = new GridLength(
                    e.NewWidth.Value -
                    numericUpDownLayoutRoot.ColumnDefinitions[0].Width.Value -
                    numericUpDownLayoutRoot.ColumnDefinitions[2].Width.Value - 5d);
            }
        }
        #endregion

        #region tbxText_MouseEnter
        private void tbxText_MouseEnter(object sender, MouseEventArgs e)
        {
            canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorderHighlighted);
            canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackgroundHighlighted);

            canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorder);
            canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorder);
            canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorder);
            canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorder);
        }
        #endregion

        #region tbxText_MouseLeave
        private void tbxText_MouseLeave(object sender, MouseEventArgs e)
        {
            if (!textBoxHasFocus)
            {
                canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackground);
                canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorder);
            }

            canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
            canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
            canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
            canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
        }
        #endregion

        #region tbxText_GotFocus
        private void tbxText_GotFocus(object sender, RoutedEventArgs e)
        {
            textBoxHasFocus = true;

            canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorderHighlighted);
            canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackgroundHighlighted);
        }
        #endregion

        #region tbxText_LostFocus
        private void tbxText_LostFocus(object sender, RoutedEventArgs e)
        {
            textBoxHasFocus = false;

            canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackground);
            canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorder);
        }
        #endregion

        #region canvasUpBackground_MouseEnter
        private void canvasUpBackground_MouseEnter(object sender, MouseEventArgs e)
        {
            SetButtonState(true, true, false);
        }
        #endregion

        #region canvasUpBackground_MouseLeave
        private void canvasUpBackground_MouseLeave(object sender, MouseEventArgs e)
        {
            SetButtonState(true, false, false);
        }
        #endregion

        #region canvasUpClickSurface_MouseLeftButtonDown
        private void canvasUpClickSurface_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            SetButtonState(true, true, true);
        }
        #endregion

        #region canvasUpClickSurface_MouseLeftButtonUp
        private void canvasUpClickSurface_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            SetButtonState(true, true, false);
        }
        #endregion

        #region canvasDownBackground_MouseEnter
        private void canvasDownBackground_MouseEnter(object sender, MouseEventArgs e)
        {
            SetButtonState(false, true, false);
        }
        #endregion

        #region canvasDownBackground_MouseLeave
        private void canvasDownBackground_MouseLeave(object sender, MouseEventArgs e)
        {
            SetButtonState(false, false, false);
        }
        #endregion

        #region canvasDownClickSurface_MouseLeftButtonDown
        private void canvasDownClickSurface_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            SetButtonState(false, true, true);
        }
        #endregion

        #region canvasDownClickSurface_MouseLeftButtonUp
        private void canvasDownClickSurface_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            SetButtonState(false, true, false);
        }
        #endregion
        #endregion

        #region Methods...
        #region SetButtonState
        private void SetButtonState(bool upButton, bool mouseOver, bool mouseDown)
        {
            if (mouseOver)
            {
                canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorderHighlighted);
                canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackgroundHighlighted);

                if (upButton)
                {
                    canvasUpInnerBorder.Margin = new Thickness(canvasUpInnerBorder.Margin.Left,
                        canvasUpInnerBorder.Margin.Top,
                        canvasUpInnerBorder.Margin.Right,
                        1);

                    canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorder);
                    canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorder);

                    if (!mouseDown)
                    {
                        canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorderHighlighted);
                        canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorderHighlighted);
                        canvasUpBackground.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownButtonBackgroundHighlighted);
                    }
                    else
                    {
                        canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorderHighlightedAndSelected);
                        canvasUpInnerBorder.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownInnerBorderHighlightedAndSelected);
                        canvasUpBackground.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownButtonBackgroundHighlightedAndSelected);
                    }
                }
                else
                {
                    canvasDownInnerBorder.Margin = new Thickness(canvasDownInnerBorder.Margin.Left,
                        1,
                        canvasDownInnerBorder.Margin.Right,
                        canvasDownInnerBorder.Margin.Bottom);

                    canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorder);
                    canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorder);

                    if (!mouseDown)
                    {
                        canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorderHighlighted);
                        canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownInnerBorderHighlighted);
                        canvasDownBackground.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownButtonBackgroundHighlighted);
                    }
                    else
                    {
                        canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownOuterBorderHighlightedAndSelected);
                        canvasDownInnerBorder.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownInnerBorderHighlightedAndSelected);
                        canvasDownBackground.Background = Helper.GetBrush(LinearGradientBrushes.NumericUpDownButtonBackgroundHighlightedAndSelected);
                    }
                }
            }
            else
            {
                if (!textBoxHasFocus)
                {
                    canvasMainBackground.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownBackground);
                    canvasMainBorder.Background = Helper.GetBrush(SolidColorBrushes.NumericUpDownMainBorder);
                }

                if (upButton)
                {
                    canvasUpInnerBorder.Margin = new Thickness(canvasUpInnerBorder.Margin.Left,
                        canvasUpInnerBorder.Margin.Top,
                        canvasUpInnerBorder.Margin.Right,
                        0);

                    canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);

                    canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasUpBackground.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                }
                else
                {
                    canvasDownInnerBorder.Margin = new Thickness(canvasDownInnerBorder.Margin.Left,
                        0,
                        canvasDownInnerBorder.Margin.Right,
                        canvasDownInnerBorder.Margin.Bottom);

                    canvasUpOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasUpInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);

                    canvasDownOuterBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasDownInnerBorder.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                    canvasDownBackground.Background = Helper.GetBrush(SolidColorBrushes.Transparent);
                }
            }
        }
        #endregion

        #region RaiseValueChangedEvent
        private void RaiseValueChangedEvent(double value)
        {
            if (ValueChanged != null)
            {
                ValueChanged(this, new ValueChangedEventArgs(value));
            }
        }
        #endregion

        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            if (!templateApplied)
            {
                numericUpDownLayoutRoot = (Grid)GetTemplateChild(NumericUpDownLayoutRoot);
                imgImage = (Image)GetTemplateChild(ImgImage);
                txtLabel = (TextBlock)GetTemplateChild(TxtLabel);
                canvasMainBorder = (Canvas)GetTemplateChild(CanvasMainBorder);
                canvasMainBackground = (Canvas)GetTemplateChild(CanvasMainBackground);
                tbxText = (TextBox)GetTemplateChild(TbxText);
                canvasUpOuterBorder = (Canvas)GetTemplateChild(CanvasUpOuterBorder);
                canvasUpInnerBorder = (Canvas)GetTemplateChild(CanvasUpInnerBorder);
                canvasUpBackground = (Canvas)GetTemplateChild(CanvasUpBackground);
                canvasUpClickSurface = (Canvas)GetTemplateChild(CanvasUpClickSurface);
                canvasDownOuterBorder = (Canvas)GetTemplateChild(CanvasDownOuterBorder);
                canvasDownInnerBorder = (Canvas)GetTemplateChild(CanvasDownInnerBorder);
                canvasDownBackground = (Canvas)GetTemplateChild(CanvasDownBackground);
                canvasDownClickSurface = (Canvas)GetTemplateChild(CanvasDownClickSurface);

                tbxText.MouseEnter += new MouseEventHandler(tbxText_MouseEnter);
                tbxText.MouseLeave += new MouseEventHandler(tbxText_MouseLeave);
                tbxText.GotFocus += new RoutedEventHandler(tbxText_GotFocus);
                tbxText.LostFocus += new RoutedEventHandler(tbxText_LostFocus);

                canvasUpClickSurface.MouseEnter += new MouseEventHandler(canvasUpBackground_MouseEnter);
                canvasUpClickSurface.MouseLeave += new MouseEventHandler(canvasUpBackground_MouseLeave);
                canvasUpClickSurface.MouseLeftButtonDown += new MouseButtonEventHandler(canvasUpClickSurface_MouseLeftButtonDown);
                canvasUpClickSurface.MouseLeftButtonUp += new MouseButtonEventHandler(canvasUpClickSurface_MouseLeftButtonUp);

                canvasDownClickSurface.MouseEnter += new MouseEventHandler(canvasDownBackground_MouseEnter);
                canvasDownClickSurface.MouseLeave += new MouseEventHandler(canvasDownBackground_MouseLeave);
                canvasDownClickSurface.MouseLeftButtonDown += new MouseButtonEventHandler(canvasDownClickSurface_MouseLeftButtonDown);
                canvasDownClickSurface.MouseLeftButtonUp += new MouseButtonEventHandler(canvasDownClickSurface_MouseLeftButtonUp);

                if (!string.IsNullOrEmpty(Label))
                    txtLabel.Text = Label;

                if (!string.IsNullOrEmpty(ImageSource))
                    imgImage.Source = new BitmapImage(new Uri(ImageSource, UriKind.Relative));

                templateApplied = true;
            }
        }
        #endregion
        #endregion

        #region Properties...
        #region ParentRibbonTabGroup
        public RibbonTabGroup ParentRibbonTabGroup
        {
            get { return parentRibbonTabGroup; }
            set { parentRibbonTabGroup = value; parentRibbonTabGroup.ColumnWidthChanged += new ColumnWidthChangedEventHandler(parentRibbonTabGroup_ColumnWidthChanged); }
        }
        #endregion

        #region Value
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        #endregion

        #region Label
        public string Label
        {
            get { return (string)GetValue(LabelProperty); }
            set { SetValue(LabelProperty, value); }
        }
        #endregion

        #region ImageSource
        public string ImageSource
        {
            get { return (string)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }
        #endregion

        #region RibbonTabGroupItemRowSpan
        public RibbonTabGroupItemRowSpan RibbonTabGroupItemRowSpan
        {
            get { return RibbonTabGroupItemRowSpan.One; }
        }
        #endregion
        #endregion
    }
    #endregion

    #region : ValueChangedEventArgs :
    public class ValueChangedEventArgs : EventArgs
    {
        #region Class Variables...
        private double value;
        #endregion

        #region Constructor(s)...
        #region ValueChangedEventArgs
        public ValueChangedEventArgs(double number)
        {
            value = number;
        }
        #endregion
        #endregion

        #region Properties...
        #region Value
        public double Value
        {
            get { return value; }
        }
        #endregion
        #endregion
    }
    #endregion
}